package com.ht.api.gaoxian;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

public class DateClusterAnalysis {
    // 聚类配置参数
    private final ClusterConfig config;

    // 聚类配置类
    public static class ClusterConfig {
        private int minClusterSize;      // 最小簇大小
        private int maxClusterSize;      // 最大簇大小
        private int maxDaysGap;          // 最大日期间隔
        private double densityThreshold;  // 密度阈值

        public ClusterConfig(int minClusterSize, int maxClusterSize, int maxDaysGap, double densityThreshold) {
            this.minClusterSize = minClusterSize;
            this.maxClusterSize = maxClusterSize;
            this.maxDaysGap = maxDaysGap;
            this.densityThreshold = densityThreshold;
        }

        // Getters
        public int getMinClusterSize() { return minClusterSize; }
        public int getMaxClusterSize() { return maxClusterSize; }
        public int getMaxDaysGap() { return maxDaysGap; }
        public double getDensityThreshold() { return densityThreshold; }
    }

    public DateClusterAnalysis(ClusterConfig config) {
        this.config = config;
    }

    // 执行聚类分析
    public List<List<LocalDate>> cluster(List<LocalDate> dates) {
        if (dates == null || dates.isEmpty()) {
            return new ArrayList<>();
        }

        // 对日期进行排序
        List<LocalDate> sortedDates = new ArrayList<>(dates);
        Collections.sort(sortedDates);

        List<List<LocalDate>> clusters = new ArrayList<>();
        List<LocalDate> currentCluster = new ArrayList<>();

        for (int i = 0; i < sortedDates.size(); i++) {
            LocalDate currentDate = sortedDates.get(i);

            if (currentCluster.isEmpty()) {
                currentCluster.add(currentDate);
                continue;
            }

            LocalDate lastDateInCluster = currentCluster.get(currentCluster.size() - 1);
            long daysBetween = ChronoUnit.DAYS.between(lastDateInCluster, currentDate);

            // 检查是否需要开始新的簇
            boolean shouldStartNewCluster =
                    daysBetween > config.getMaxDaysGap() ||
                            currentCluster.size() >= config.getMaxClusterSize();

            if (shouldStartNewCluster) {
                if (isValidCluster(currentCluster)) {
                    clusters.add(new ArrayList<>(currentCluster));
                }
                currentCluster = new ArrayList<>();
            }

            currentCluster.add(currentDate);
        }

        // 处理最后一个簇
        if (isValidCluster(currentCluster)) {
            clusters.add(currentCluster);
        }

        return clusters;
    }

    // 验证聚类是否有效
    private boolean isValidCluster(List<LocalDate> cluster) {
        if (cluster.size() < config.getMinClusterSize() ||
                cluster.size() > config.getMaxClusterSize()) {
            return false;
        }

        // 验证最大间隔
        for (int i = 1; i < cluster.size(); i++) {
            long gap = ChronoUnit.DAYS.between(cluster.get(i-1), cluster.get(i));
            if (gap > config.getMaxDaysGap()) {
                return false;
            }
        }

        // 验证密度
        double clusterDays = ChronoUnit.DAYS.between(
                cluster.get(0),
                cluster.get(cluster.size() - 1)
        ) + 1;

        double density = cluster.size() / clusterDays;
        return density >= config.getDensityThreshold();
    }

    // 获取聚类统计信息
    public List<ClusterStats> getClusterStats(List<List<LocalDate>> clusters) {
        List<ClusterStats> stats = new ArrayList<>();
        for (List<LocalDate> cluster : clusters) {
            if (!cluster.isEmpty()) {
                LocalDate start = cluster.get(0);
                LocalDate end = cluster.get(cluster.size() - 1);
                long days = ChronoUnit.DAYS.between(start, end) + 1;
                double density = (double) cluster.size() / days;

                stats.add(new ClusterStats(
                        start, end, cluster.size(), days, density
                ));
            }
        }
        return stats;
    }

    // 聚类统计信息类
    public static class ClusterStats {
        private LocalDate startDate;
        private LocalDate endDate;
        private int count;
        private long daySpan;
        private double density;

        public ClusterStats(LocalDate startDate, LocalDate endDate,
                            int count, long daySpan, double density) {
            this.startDate = startDate;
            this.endDate = endDate;
            this.count = count;
            this.daySpan = daySpan;
            this.density = density;
        }

        @Override
        public String toString() {
            return String.format(
                    "时间范围: %s 至 %s\n数据点数量: %d\n跨度天数: %d\n密度: %.4f(点/天)",
                    startDate, endDate, count, daySpan, density
            );
        }
    }

    // 展示聚类结果
    public void demonstrateClusteringWithConfig(List<LocalDate> dates, ClusterConfig config) {
        List<List<LocalDate>> clusters = this.cluster(dates);
        List<ClusterStats> stats = this.getClusterStats(clusters);

        System.out.println("配置参数:");
        System.out.printf("最小簇大小: %d\n", config.getMinClusterSize());
        System.out.printf("最大簇大小: %d\n", config.getMaxClusterSize());
        System.out.printf("最大间隔天数: %d\n", config.getMaxDaysGap());
        System.out.printf("密度阈值: %.2f\n", config.getDensityThreshold());

        System.out.println("\n聚类结果:");
        for (int i = 0; i < stats.size(); i++) {
            System.out.println("\n簇 " + (i + 1) + ":");
            System.out.println(stats.get(i));
        }
    }

    // 获取聚类结果（不打印）
    public List<ClusterStats> getClusteringResult(List<LocalDate> dates) {
        List<List<LocalDate>> clusters = this.cluster(dates);
        return this.getClusterStats(clusters);
    }
}
